use pest::Parser;
use pest_derive::Parser;
use std::collections::HashMap;

#[derive(Parser)]
#[grammar = "json.pest"]
pub struct JSONParser;

#[derive(Debug, PartialEq, Clone)]
pub enum JsonValue {
    String(String),
    Number(f64),
    Boolean(bool),
    Array(Vec<JsonValue>),
    Object(HashMap<String, JsonValue>),
    Null,
}

pub fn parse_json(input: &str) -> Result<JsonValue, pest::error::Error<Rule>> {
    let mut pairs = JSONParser::parse(Rule::value, input)?;
    Ok(parse_value(pairs.next().unwrap()))
}

fn parse_value(pair: pest::iterators::Pair<Rule>) -> JsonValue {
    match pair.as_rule() {
        Rule::string => JsonValue::String(parse_string(pair)),
        Rule::number => JsonValue::Number(parse_number(pair)),
        Rule::boolean => JsonValue::Boolean(parse_boolean(pair)),
        Rule::null => JsonValue::Null,
        Rule::array => JsonValue::Array(parse_array(pair)),
        Rule::object => JsonValue::Object(parse_object(pair)),
        _ => unreachable!(),
    }
}

fn parse_string(pair: pest::iterators::Pair<Rule>) -> String {
    // 移除引号并处理转义字符
    let inner = pair.into_inner().next().unwrap().as_str();
    // 简化处理，实际应用中需要完整处理转义字符
    inner.replace("\\\"", "\"").replace("\\\\", "\\")
}

fn parse_number(pair: pest::iterators::Pair<Rule>) -> f64 {
    pair.as_str().parse().unwrap()
}

fn parse_boolean(pair: pest::iterators::Pair<Rule>) -> bool {
    match pair.as_str() {
        "true" => true,
        "false" => false,
        _ => unreachable!(),
    }
}

fn parse_array(pair: pest::iterators::Pair<Rule>) -> Vec<JsonValue> {
    pair.into_inner()
        .map(|value_pair| parse_value(value_pair))
        .collect()
}

fn parse_object(pair: pest::iterators::Pair<Rule>) -> HashMap<String, JsonValue> {
    pair.into_inner()
        .map(|pair_pair| {
            let mut inner_pairs = pair_pair.into_inner();
            let key = parse_string(inner_pairs.next().unwrap());
            let value = parse_value(inner_pairs.next().unwrap());
            (key, value)
        })
        .collect()
}

// 为了方便使用，添加一些辅助方法
impl JsonValue {
    pub fn as_str(&self) -> Option<&str> {
        match self {
            JsonValue::String(s) => Some(s),
            _ => None,
        }
    }

    pub fn as_number(&self) -> Option<f64> {
        match self {
            JsonValue::Number(n) => Some(*n),
            _ => None,
        }
    }

    pub fn as_bool(&self) -> Option<bool> {
        match self {
            JsonValue::Boolean(b) => Some(*b),
            _ => None,
        }
    }

    pub fn as_array(&self) -> Option<&Vec<JsonValue>> {
        match self {
            JsonValue::Array(arr) => Some(arr),
            _ => None,
        }
    }

    pub fn as_object(&self) -> Option<&HashMap<String, JsonValue>> {
        match self {
            JsonValue::Object(obj) => Some(obj),
            _ => None,
        }
    }

    pub fn is_null(&self) -> bool {
        matches!(self, JsonValue::Null)
    }
}

fn main() {
    let json_str = r#"
    {
        "name": "John Doe",
        "age": 30,
        "is_student": false,
        "hobbies": ["reading", "swimming"],
        "address": {
            "street": "123 Main St",
            "city": "New York"
        },
        "scores": [95.5, 87.3, 92.1],
        "nullable": null
    }
    "#;

    match parse_json(json_str) {
        Ok(json_value) => {
            println!("解析成功!");
            println!("{:#?}", json_value);
            
            // 访问具体值
            if let Some(obj) = json_value.as_object() {
                if let Some(JsonValue::String(name)) = obj.get("name") {
                    println!("Name: {}", name);
                }
                if let Some(JsonValue::Number(age)) = obj.get("age") {
                    println!("Age: {}", age);
                }
            }
        }
        Err(e) => {
            println!("解析错误: {}", e);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_basic_types() {
        assert!(parse_json(r#""hello""#).is_ok());
        assert!(parse_json("123.45").is_ok());
        assert!(parse_json("true").is_ok());
        assert!(parse_json("false").is_ok());
        assert!(parse_json("null").is_ok());
    }

    #[test]
    fn test_array() {
        assert!(parse_json(r#"[1, "two", true]"#).is_ok());
    }

    #[test]
    fn test_object() {
        assert!(parse_json(r#"{"key": "value"}"#).is_ok());
    }
}